/*************************************************************************
        > File Name: sysinfo.cpp
        > Author: xuwenlong
        > Mail: myxuan475@126.com
        > Created Time: 2018年07月17日 星期二 16时09分32秒
 ************************************************************************/
#include "sysinfo.h"
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <error.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <utils/logger.h>

namespace settings {
namespace sysinfo {
double cal_occupy(CPU_OCCUPY *o, CPU_OCCUPY *n)
{
    double od, nd;
    double id, sd;
    double scale;
    od = (double)(o->user + o->nice + o->system + o->idle); // 第一次(用户+优先级+系统+空闲)的时间再赋给od
    nd = (double)(n->user + n->nice + n->system + n->idle); // 第二次(用户+优先级+系统+空闲)的时间再赋给od
    scale = 100.0 / (float)(nd - od);     // 100除强制转换(nd-od)之差为float类型再赋给scale这个变量
    id = (double)(n->user - o->user);     // 用户第一次和第二次的时间之差再赋给id
    sd = (double)(n->system - o->system); // 系统第一次和第二次的时间之差再赋给sd
    return ((sd + id) * 100.0) / (nd - od); //((用户+系统)乖100)除(第一次和第二次的时间差)再赋给g_cpu_used
}

void get_occupy(CPU_OCCUPY *o)
{
    FILE *fd;
    int n;
    char buff[MAXBUFSIZE];
    fd = fopen("/proc/stat",
        "r"); // 这里只读取stat文件的第一行及cpu总信息，如需获取每核cpu的使用情况，请分析stat文件的接下来几行。
    (void)fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %u %u %u %u", o->name, &o->user, &o->nice, &o->system, &o->idle);
    fclose(fd);
}

void get_mem_occupy(MEM_OCCUPY *mem)
{
    FILE *fd;
    char buff[MAXBUFSIZE];
    fd = fopen("/proc/meminfo", "r");
    (void)fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %lld", mem->name, &mem->total);
    (void)fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %lld", mem->name2, &mem->free);
    fclose(fd);
}

float get_io_occupy()
{
    char cmd[] = "iostat -d -k";
    char buffer[MAXBUFSIZE];
    char a[20];
    float arr[20];
    FILE *pipe = popen(cmd, "r");
    if (!pipe)
        return -1;
    (void)fgets(buffer, sizeof(buffer), pipe);
    (void)fgets(buffer, sizeof(buffer), pipe);
    (void)fgets(buffer, sizeof(buffer), pipe);
    (void)fgets(buffer, sizeof(buffer), pipe);
    sscanf(buffer, "%s %f %f %f %f %f %f %f %f %f %f %f %f %f ", a, &arr[0], &arr[1], &arr[2], &arr[3], &arr[4],
        &arr[5], &arr[6], &arr[7], &arr[8], &arr[9], &arr[10], &arr[11], &arr[12]);
    // printf("%f\n",arr[12]);

    pclose(pipe);
    return arr[12];
}
void get_disk_occupy(char **reused)
{
    char currentDirectoryPath[MAXBUFSIZE];
    (void)getcwd(currentDirectoryPath, MAXBUFSIZE);
    // printf("当前目录：%s\n",currentDirectoryPath);
    char cmd[50] = "df ";
    strcat(cmd, currentDirectoryPath);
    // printf("%s\n",cmd);

    char buffer[MAXBUFSIZE];
    FILE *pipe = popen(cmd, "r");
    char fileSys[20];
    char blocks[20];
    char used[20];
    char free[20];
    char percent[10];
    char moment[20];

    if (!pipe)
        return;
    if (fgets(buffer, sizeof(buffer), pipe) != NULL) {
        sscanf(buffer, "%s %s %s %s %s %s", fileSys, blocks, used, free, percent, moment);
    }
    if (fgets(buffer, sizeof(buffer), pipe) != NULL) {
        sscanf(buffer, "%s %s %s %s %s %s", fileSys, blocks, used, free, percent, moment);
    }
    // printf("desk used:%s\n",percent);
    strcpy(*reused, percent);
    pclose(pipe);
    return;
}

void getCurrentDownloadRates(long int *save_rate)
{
    char intface[] = "eth0:"; // 这是网络接口名，根据主机配置
    // char intface[] = "wlan0:";
    FILE *net_dev_file;
    char buffer[1024];
    size_t bytes_read;
    char *match;
    if ((net_dev_file = fopen("/proc/net/dev", "r")) == NULL) {
        HTELINK_LOG_ERR("open /proc/net/dev error, %s", strerror(errno));
        //        exit(EXIT_FAILURE);
        return;
    }

    int i = 0;
    while (i++ < 20) {
        if (fgets(buffer, sizeof(buffer), net_dev_file) != NULL) {
            if (strstr(buffer, intface) != NULL) {
                // printf("%d   %s\n",i,buffer);
                sscanf(buffer, "%s %ld", buffer, save_rate);
                break;
            }
        }
    }
    if (i == 20)
        *save_rate = 0.01;
    fclose(net_dev_file); // 关闭文件
    return;
}

int SetIfAddr(const char *ifname, const char *Ipaddr, const char *mask, const char *gateway)
{
    int fd;
    int rc;
    struct ifreq ifr;
    struct sockaddr_in *sin;
    struct rtentry rt;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        HTELINK_LOG_ERR("socket %s,  error, %s", ifname, strerror(errno));
        return fd;
    }
    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, ifname);
    sin = (struct sockaddr_in *)&ifr.ifr_addr;
    sin->sin_family = AF_INET;

    // ipaddr
    if ((rc = inet_aton(Ipaddr, &(sin->sin_addr))) < 0) {
        HTELINK_LOG_ERR("inet_aton %s, error, %s", ifname, strerror(errno));
        close(fd);
        return rc;
    }

    if ((rc = ioctl(fd, SIOCSIFADDR, &ifr)) < 0) {
        HTELINK_LOG_ERR("ioctl ifaddr %s, error, %s", ifname, strerror(errno));
        close(fd);
        return rc;
    }

    // netmask
    if ((rc = inet_aton(mask, &(sin->sin_addr))) < 0) {
        HTELINK_LOG_ERR("inet_aton %s,  mask error, %s", ifname, strerror(errno));
        close(fd);
        return rc;
    }
    if ((rc = ioctl(fd, SIOCSIFNETMASK, &ifr)) < 0) {
        HTELINK_LOG_ERR("ioctl %s, netmask error, %s", ifname, strerror(errno));
        close(fd);
        return rc;
    }

    // gateway
    memset(&rt, 0, sizeof(struct rtentry));
    memset(sin, 0, sizeof(struct sockaddr_in));
    sin->sin_family = AF_INET;
    sin->sin_port = 0;
    if ((rc = inet_aton(gateway, &sin->sin_addr)) < 0) {
        HTELINK_LOG_ERR("inet_aton %s, error, %s", ifname, strerror(errno));
    }
    memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
    ((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
    ((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
    rt.rt_flags = RTF_GATEWAY;
    if ((rc = ioctl(fd, SIOCADDRT, &rt)) < 0) {
        HTELINK_LOG_ERR("ioctl(SIOCADDRT)  %s error in set_default_route, %s", ifname, strerror(errno));
        close(fd);
        return rc;
    }
    close(fd);
    return 0;
}

/*
 * 获取IP
 */
int GetIfAddr(const char *iface, char ipaddr[], char mask[], char gateway[])
{
    int sockfd;
    int rc;
    struct sockaddr_in *sin;
    struct ifreq ifr_ip;
    struct rtentry rt;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        HTELINK_LOG_ERR("%s socket create failse...GetLocalIp! %s", iface, strerror(errno));
        return sockfd;
    }

    /* zero struct */
    memset(&ifr_ip, 0, sizeof(ifr_ip));
    strncpy(ifr_ip.ifr_name, iface, sizeof(ifr_ip.ifr_name) - 1);

    /* get ip */
    if ((rc = ioctl(sockfd, SIOCGIFADDR, &ifr_ip)) < 0) {
        HTELINK_LOG_ERR("ioctl ip %s,  error, %s", iface, strerror(errno));
        close(sockfd);
        return rc;
    }
    sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;
    strcpy(ipaddr, inet_ntoa(sin->sin_addr));

    /* get netmask */
    if ((rc = ioctl(sockfd, SIOCGIFNETMASK, &ifr_ip)) < 0) {
        HTELINK_LOG_ERR("netmask ioctl %s,  error, %s", iface, strerror(errno));
        close(sockfd);
        return rc;
    }
    sin = (struct sockaddr_in *)&(ifr_ip.ifr_netmask);
    strcpy(mask, inet_ntoa(sin->sin_addr));

    /* gateway */
    if ((rc = ioctl(sockfd, SIOCGIFCONF, &ifr_ip)) < 0) {
        HTELINK_LOG_ERR("gateway ioctl %s,  error, %s", iface, strerror(errno));
        close(sockfd);
        return rc;
    }
    sin = (struct sockaddr_in *)&(ifr_ip.ifr_addr);
    inet_ntop(AF_INET, &sin->sin_addr, gateway, INET_ADDRSTRLEN);

    close(sockfd);

    return rc;
}

/*
 * 获取IP
 */
bool GetLocalIp(char ipaddr[])
{
    return GetLocalIp("eth0", ipaddr);
}

bool GetLocalIp(const char *iface, char ipaddr[])
{
    int sock_get_ip;

    struct sockaddr_in *sin;
    struct ifreq ifr_ip;

    if ((sock_get_ip = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("socket create failse...GetLocalIp!/n");
        return false;
    }

    memset(&ifr_ip, 0, sizeof(ifr_ip));
    strncpy(ifr_ip.ifr_name, iface, sizeof(ifr_ip.ifr_name) - 1);

    if (ioctl(sock_get_ip, SIOCGIFADDR, &ifr_ip) < 0) {
        return false;
    }
    sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;
    strcpy(ipaddr, inet_ntoa(sin->sin_addr));

    printf("local ip:%s /n", ipaddr);
    close(sock_get_ip);

    return true;
}

/*
 * 修改本机IP地址的函数
 */
int SetLocalIp(const char *iface, const char *ipaddr)
{
    int sock_set_ip;

    struct sockaddr_in sin_set_ip;
    struct ifreq ifr_set_ip;

    bzero(&ifr_set_ip, sizeof(ifr_set_ip));

    if (ipaddr == NULL)
        return -1;

    if (sock_set_ip = socket(AF_INET, SOCK_STREAM, 0) == -1)
        ;
    {
        perror("socket create failse...SetLocalIp!/n");
        return -1;
    }

    memset(&sin_set_ip, 0, sizeof(sin_set_ip));
    strncpy(ifr_set_ip.ifr_name, iface, sizeof(ifr_set_ip.ifr_name) - 1);

    sin_set_ip.sin_family = AF_INET;
    sin_set_ip.sin_addr.s_addr = inet_addr(ipaddr);
    memcpy(&ifr_set_ip.ifr_addr, &sin_set_ip, sizeof(sin_set_ip));

    if (ioctl(sock_set_ip, SIOCSIFADDR, &ifr_set_ip) < 0) {
        perror("Not setup interface/n");
        return -1;
    }

    // 设置激活标志
    ifr_set_ip.ifr_flags |= IFF_UP | IFF_RUNNING;

    // get the status of the device
    if (ioctl(sock_set_ip, SIOCSIFFLAGS, &ifr_set_ip) < 0) {
        perror("SIOCSIFFLAGS");
        return -1;
    }

    close(sock_set_ip);
    return 0;
}

/*
 *获取子网掩码的函数
 */
bool GetLocalNetMask(const char *ifname, char netmask_addr[])
{
    int sock_netmask;

    struct ifreq ifr_mask;
    struct sockaddr_in *net_mask;

    sock_netmask = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_netmask == -1) {
        perror("create socket failture...GetLocalNetMask/n");
        return false;
    }

    memset(&ifr_mask, 0, sizeof(ifr_mask));
    strncpy(ifr_mask.ifr_name, ifname, sizeof(ifr_mask.ifr_name) - 1);

    if ((ioctl(sock_netmask, SIOCGIFNETMASK, &ifr_mask)) < 0) {
        printf("mac ioctl error/n");
        return false;
    }

    net_mask = (struct sockaddr_in *)&(ifr_mask.ifr_netmask);
    strcpy(netmask_addr, inet_ntoa(net_mask->sin_addr));

    printf("local netmask:%s/n", netmask_addr);

    close(sock_netmask);
    return true;
}

/*
 * 修改子NETMASK的函数
 */
bool SetLocalNetMask(const char *iface, const char *szNetMask)
{
    int sock_netmask;
    char netmask_addr[32];

    struct ifreq ifr_mask;
    struct sockaddr_in *sin_net_mask;

    sock_netmask = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_netmask == -1) {
        perror("Not create network socket connect/n");
        return false;
    }

    memset(&ifr_mask, 0, sizeof(ifr_mask));
    strncpy(ifr_mask.ifr_name, iface, sizeof(ifr_mask.ifr_name) - 1);
    sin_net_mask = (struct sockaddr_in *)&ifr_mask.ifr_addr;
    sin_net_mask->sin_family = AF_INET;
    inet_pton(AF_INET, szNetMask, &sin_net_mask->sin_addr);

    if (ioctl(sock_netmask, SIOCSIFNETMASK, &ifr_mask) < 0) {
        printf("sock_netmask ioctl error/n");
        return false;
    }
    return true;
}

/*
 * 获去GateWay
 */
bool GetGateWay(char gateway[])
{
    FILE *fp;
    char buf[512];
    char cmd[128];

    strcpy(cmd, "route -n|grep 'UG'");
    fp = popen(cmd, "r");
    if (NULL == fp) {
        perror("popen error");
        return false;
    }

    size_t r = fread(buf, 1, sizeof(buf), fp);
    sscanf(buf, "%*s%s", gateway);
    pclose(fp);

    return true;
}

/*
 * 设置网关
 */
int SetGateWay(const char *szGateWay)
{
    int ret = 0;
    char cmd[128];
    char strGW[50];

    GetGateWay(strGW);

    strcpy(cmd, "route del default gw ");
    strcat(cmd, strGW);
    ret = system(cmd);
    if (ret < 0) {
        perror("route error");
        return -1;
    }
    strcpy(cmd, "route add default gw ");
    strcat(cmd, szGateWay);

    ret = system(cmd);
    if (ret < 0) {
        perror("route error");
        return -1;
    }

    return ret;
}

/*
 *获取本机MAC地址函数
 */
bool GetLocalMac(const char *eth, char mac_addr[30])
{
    int sock_mac;
    struct ifreq ifr_mac;

    sock_mac = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_mac == -1) {
        perror("create socket falise...mac");
        return false;
    }

    memset(&ifr_mac, 0, sizeof(ifr_mac));
    strncpy(ifr_mac.ifr_name, eth, sizeof(ifr_mac.ifr_name) - 1);

    if ((ioctl(sock_mac, SIOCGIFHWADDR, &ifr_mac)) < 0) {
        printf("mac ioctl error/n");
        return false;
    }

    sprintf(mac_addr, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned char)ifr_mac.ifr_hwaddr.sa_data[0],
        (unsigned char)ifr_mac.ifr_hwaddr.sa_data[1], (unsigned char)ifr_mac.ifr_hwaddr.sa_data[2],
        (unsigned char)ifr_mac.ifr_hwaddr.sa_data[3], (unsigned char)ifr_mac.ifr_hwaddr.sa_data[4],
        (unsigned char)ifr_mac.ifr_hwaddr.sa_data[5]);

    printf("local mac:%s /n", mac_addr);

    close(sock_mac);
    return true;
}
} // namespace sysinfo
} // namespace settings